

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/favicon.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="Blue~u~u~u">
  <meta name="author" content="Blue~u~u~u">
  <meta name="keywords" content="">
  <meta name="description" content="synchronized 底层原理探究第一节 锁膨胀机制1、JDK 1.6 分水岭在 JDK 1.6 之前，synchronized 的底层工作机制只有『重量级锁』这一种模式。从 JDK 1.6 开始，官方对synchronized 的底层工作机制做了重大调整。 为了减少获得锁和释放锁带来的性能消耗，引入了『偏向锁』和『轻量级锁』的概念。升级后锁一共有 4 种状态，级别从低到高依次是：无锁状态、偏">
<meta property="og:type" content="article">
<meta property="og:title" content="JUC学习笔记（二）synchronized 底层原理探究">
<meta property="og:url" content="http://www.slx.blue/2022/03/08/JUC02-synchronized/index.html">
<meta property="og:site_name" content="Blue~u~u~u~u">
<meta property="og:description" content="synchronized 底层原理探究第一节 锁膨胀机制1、JDK 1.6 分水岭在 JDK 1.6 之前，synchronized 的底层工作机制只有『重量级锁』这一种模式。从 JDK 1.6 开始，官方对synchronized 的底层工作机制做了重大调整。 为了减少获得锁和释放锁带来的性能消耗，引入了『偏向锁』和『轻量级锁』的概念。升级后锁一共有 4 种状态，级别从低到高依次是：无锁状态、偏">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-01.jpg?versionId=CAEQKRiBgIDQo6WS.xciIDVlMjUyYWY3NDc2NzRlYTM4ZDc4YmQ4ZDJlODA4MDhm">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-02.jpg?versionId=CAEQKRiBgIDOsv2i.xciIGUxMmI3MTU3MmYzZDQxNDBiMzFlYTVhODNkZWMwNDVm">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-03.jpg?versionId=CAEQKRiBgIDNsv2i.xciIDg1M2UxNmZlNmVhNDRiZjJhMGE2YTQzNTk5YTE0MmIz">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-04.jpg?versionId=CAEQKRiBgMDLsv2i.xciIDQ2MDg0OWJkYTg4YTRlMjY4MjhjZjQzYjAxNjk0ZTBi">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-05.jpg?versionId=CAEQKRiBgIDKsv2i.xciIGE0YjEyN2YzMDUwMDQ3ZWNhZjAyZmFmMGI0YWFhOGM1">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-06.jpg?versionId=CAEQKRiBgIDIsv2i.xciIGNiYzcxZGI5YTA0YjQyYThhZjY5YWNjODYyOTQyMmRk">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-07.jpg?versionId=CAEQKRiBgMCVsf2i.xciIDBmZjU2NGJhN2U0YTRiYWRhZDU1YzFiYjZjOWE0NzYz">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-08.jpg?versionId=CAEQKRiBgICSsf2i.xciIGYwYzE2OGM3NjBlODRhOGRiOThhNjllYzQ2NWE4NzZj">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-09.jpg?versionId=CAEQKRiBgICOsf2i.xciIGQ3YmY2ZTI0ZGJkMDQyYzJhZGYyZDQwN2M3MTlkOTRk">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-10.jpg?versionId=CAEQKRiBgMCNsf2i.xciIGJiOTJhNTZiYWQ4ODQyMGZhZmMyMDRjZmYzMjE1YzJj">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-11.jpg?versionId=CAEQKRiBgMD4sP2i.xciIDdiMmM0NTlmMTMwYzRlMGFhM2Q1ZmE4MTBkZDIyODVm">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-12.jpg?versionId=CAEQKRiBgID0sP2i.xciIGZlNzVhMzI4MDg0OTQ2M2NhMjNhYTlmY2UwZTNkZDY1">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-13.jpg?versionId=CAEQKRiBgMD3sP2i.xciIDQ2ZjgyM2ZmYzQ0MzQxODJhMGE2ODE2NzMzYWUwMDAy">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-14.jpg?versionId=CAEQKRiBgIDxsP2i.xciIGEyMTQ4NzdkYzBhYTRkNjZhMTBmYmY4OGQyZGQ0NjY1">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-15.jpg?versionId=CAEQKRiBgIDwsP2i.xciIGI0NzQ5NDE0ZDA0NTQxOTViNWRkMjE0ZTkxNWY2YWZi">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-16.jpg?versionId=CAEQKRiBgIDvsP2i.xciIDBkNjk1YTdlMzk2YTRkMzU5MWFkMjQyZjdjMzdmNmI4">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-17.jpg?versionId=CAEQKRiBgICzr_2i.xciIDQwMTVlOGJiYjM4YjRhMWJiY2NkMDE1ZjkxMDk0Y2Vh">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-18.jpg?versionId=CAEQKRiBgMC5r_2i.xciIDYzYjBkNGY4NTY0NjRjMjRiYTVmZjBhYTJhZWE1NWMy">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-19.jpg?versionId=CAEQKRiCgICzr_2i.xciIDlmMTIyNGI2OWI0ZjQzNDE4OGJiNDA5NDkyZjIwNGM5">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-20.jpg?versionId=CAEQKRiBgMCkr_2i.xciIGE2MmU0MmRkZGJlOTQ1ZTFiZjg2MjQ4ZDI1YmM5MDk4">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-21.jpg?versionId=CAEQKRiBgMCfr_2i.xciIDk0YWU1NzRlMmE5MzQzMThhZTRlY2FkOTJmZTVlMmE1">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-22.jpg?versionId=CAEQKRiBgICbr_2i.xciIDA3ZTcwMjM4YmZhZjQwNzI4M2JhNmEzNGVjNDFhNWFh">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-23.jpg?versionId=CAEQKRiBgICrr_2i.xciIGE5NDA3YWE2NjY4NzRjMWJiOTcyNTFiNGRlYzg2YmRh">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-24.png?versionId=CAEQKRiBgMC33bLH.xciIGEwYjE2ZGY2OTQ3OTRjMjZhNjUwZjBhYTA3MWU5ZTky">
<meta property="article:published_time" content="2022-03-08T10:13:21.000Z">
<meta property="article:modified_time" content="2022-03-10T03:23:27.249Z">
<meta property="article:author" content="Blue~u~u~u">
<meta property="article:tag" content="JUC">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-01.jpg?versionId=CAEQKRiBgIDQo6WS.xciIDVlMjUyYWY3NDc2NzRlYTM4ZDc4YmQ4ZDJlODA4MDhm">
  
  <title>JUC学习笔记（二）synchronized 底层原理探究 - Blue~u~u~u~u</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"www.slx.blue","root":"/","version":"1.8.12","typing":{"enable":true,"typeSpeed":180,"cursorChar":"_","loop":true},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname"}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.0"></head>

<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css"/>
<script src="/live2d-widget/autoload.js"></script>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Blue~u~u</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                友链
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/images/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="JUC学习笔记（二）synchronized 底层原理探究">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2022-03-08 18:13" pubdate>
        2022年3月8日 晚上
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      9.2k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      29 分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">JUC学习笔记（二）synchronized 底层原理探究</h1>
            
              <p class="note note-info">
                
                  本文最后更新于：3 个月前
                
              </p>
            
            <div class="markdown-body">
              <h1 id="synchronized-底层原理探究"><a href="#synchronized-底层原理探究" class="headerlink" title="synchronized 底层原理探究"></a>synchronized 底层原理探究</h1><h1 id="第一节-锁膨胀机制"><a href="#第一节-锁膨胀机制" class="headerlink" title="第一节 锁膨胀机制"></a>第一节 锁膨胀机制</h1><h2 id="1、JDK-1-6-分水岭"><a href="#1、JDK-1-6-分水岭" class="headerlink" title="1、JDK 1.6 分水岭"></a>1、JDK 1.6 分水岭</h2><p>在 JDK 1.6 之前，synchronized 的底层工作机制只有『重量级锁』这一种模式。从 JDK 1.6 开始，官方对synchronized 的底层工作机制做了重大调整。</p>
<p>为了减少获得锁和释放锁带来的性能消耗，引入了『偏向锁』和『轻量级锁』的概念。升级后锁一共有 4 种状态，级别从低到高依次是：无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。<strong>锁可以升级但不能降级，也称为膨胀过程不可逆</strong>。</p>
<h2 id="2、锁膨胀-重点"><a href="#2、锁膨胀-重点" class="headerlink" title="2、锁膨胀 [重点]"></a>2、锁膨胀 [重点]</h2><h3 id="①无锁"><a href="#①无锁" class="headerlink" title="①无锁"></a>①无锁</h3><p>对象（用来作为锁对象的那个）刚创建出来，没有线程来竞争——没有线程准备执行同步代码块。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-01.jpg?versionId=CAEQKRiBgIDQo6WS.xciIDVlMjUyYWY3NDc2NzRlYTM4ZDc4YmQ4ZDJlODA4MDhm" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="②偏向锁"><a href="#②偏向锁" class="headerlink" title="②偏向锁"></a>②偏向锁</h3><p><strong>只有一个线程访问</strong>对象。此时没有必要执行获得锁和释放锁的操作，我们只需要在对象中记录当前偏向的线程的 ID，只要是这个线程来访问对象，则无需获得锁，直接可以开始操作。</p>
<p>如果一个线程获得了锁，那么锁就进入偏向模式，此时 Mark Word 的结构也就变为偏向锁结构，当该线程再次请求锁时，无需再做任何同步操作（同步操作就是加锁、解锁操作的总称），即获取锁的过程只需要检查 Mark Word 的锁标记位为偏向锁以及当前线程 ID 等于 Mark Word 的 Thread ID 即可，这样就省去了大量有关锁申请的操作。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-02.jpg?versionId=CAEQKRiBgIDOsv2i.xciIGUxMmI3MTU3MmYzZDQxNDBiMzFlYTVhODNkZWMwNDVm" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="③轻量级锁"><a href="#③轻量级锁" class="headerlink" title="③轻量级锁"></a>③轻量级锁</h3><p>轻量级锁是由偏向锁升级而来，当存在第二个线程申请同一个锁对象时，偏向锁就会立即升级为轻量级锁。注意这里的第二个线程<strong>只是申请锁</strong>，<strong>不存在</strong>两个线程同时<strong>竞争</strong>锁，可以是一前一后地交替执行同步块。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-03.jpg?versionId=CAEQKRiBgIDNsv2i.xciIDg1M2UxNmZlNmVhNDRiZjJhMGE2YTQzNTk5YTE0MmIz" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="④重量级锁"><a href="#④重量级锁" class="headerlink" title="④重量级锁"></a>④重量级锁</h3><p>重量级锁是由轻量级锁升级而来。当同一时间有多个线程竞争锁时，锁就会被升级成重量级锁，此时其申请锁带来的开销也就变大。此时各个线程之间<strong>存在竞争关系</strong>。</p>
<p>重量级锁一般用在不追求吞吐量，同步块或者同步方法执行时间较长的场景。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-04.jpg?versionId=CAEQKRiBgMDLsv2i.xciIDQ2MDg0OWJkYTg4YTRlMjY4MjhjZjQzYjAxNjk0ZTBi" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="3、锁消除-了解"><a href="#3、锁消除-了解" class="headerlink" title="3、锁消除 [了解]"></a>3、锁消除 [了解]</h2><p>消除锁是 JVM 的另外一种锁的优化。在 JIT 编译时，对运行上下文进行扫描，去除不可能存在竞争的锁。比如下面代码的 method01() 和method02() 的执行效率是一样的，因为 objectLock 锁对象是局部变量，每个线程都可以创建属于自己的锁对象，所以事实上并不存在锁的竞争关系。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-05.jpg?versionId=CAEQKRiBgIDKsv2i.xciIGE0YjEyN2YzMDUwMDQ3ZWNhZjAyZmFmMGI0YWFhOGM1" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="4、锁粗化-了解"><a href="#4、锁粗化-了解" class="headerlink" title="4、锁粗化 [了解]"></a>4、锁粗化 [了解]</h2><p>锁粗化是虚拟机对另一种极端情况的优化处理，通过扩大锁的范围，避免反复加锁和释放锁。比如下面 method03() 经过锁粗化优化之后就和 method04() 执行效率一样了。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-06.jpg?versionId=CAEQKRiBgIDIsv2i.xciIGNiYzcxZGI5YTA0YjQyYThhZjY5YWNjODYyOTQyMmRk" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="5、自旋锁"><a href="#5、自旋锁" class="headerlink" title="5、自旋锁"></a>5、自旋锁</h2><p>轻量级锁失败后，虚拟机为了避免线程真实地在操作系统层面挂起，还会进行一项称为自旋锁的优化手段。大致相当于：在遇到 synchronized 时，没有拿到锁，但是并不乖乖去阻塞，而是继续执行一些无意义代码。执行完这些代码再看看别人把锁释放没有。如果还是没有释放，那就只好去阻塞了。</p>
<ul>
<li>适合的场景：锁定时间较短，通过自旋有较大几率获得锁。</li>
<li>不适合的场景：锁定时间长，自旋操作本身浪费了 CPU 性能。<ul>
<li>通俗来说就是：“旋”了半天没等到，白“旋”了。</li>
</ul>
</li>
</ul>
<p>自旋代码举例：这例子只是拿常规代码说明一下情况并不能代表底层实际执行效果</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java">System.out.println(<span class="hljs-string">&quot;正常业务功能代码 ……&quot;</span>); <span class="hljs-comment">// Runnable 或 Running 状态</span><br>System.out.println(<span class="hljs-string">&quot;正常业务功能代码 ……&quot;</span>); <span class="hljs-comment">// Runnable 或 Running 状态</span><br>System.out.println(<span class="hljs-string">&quot;正常业务功能代码 ……&quot;</span>); <span class="hljs-comment">// Runnable 或 Running 状态</span><br><br><span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10</span>; i++) &#123;<br>    System.out.println(<span class="hljs-string">&quot;自旋代码 ……&quot;</span>); <span class="hljs-comment">// Runnable 或 Running 状态</span><br>&#125;<br><br><span class="hljs-comment">// 自旋完成</span><br><span class="hljs-comment">// 尝试获取锁</span><br><span class="hljs-comment">// 获取成功：进入同步代码块执行代码</span><br><span class="hljs-comment">// 获取失败：进入阻塞状态</span><br><br><span class="hljs-keyword">synchronized</span> (Demo05Spin.class) &#123;<br><br>&#125;<br></code></pre></td></tr></table></figure>



<h2 id="6、自适应自旋锁"><a href="#6、自适应自旋锁" class="headerlink" title="6、自适应自旋锁"></a>6、自适应自旋锁</h2><p>这种相当于是对上面自旋锁优化方式的进一步优化，它的自旋的次数不再固定，其自旋的次数由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定，这就解决了自旋锁带来的缺点。</p>
<h1 id="第二节-对象存储结构"><a href="#第二节-对象存储结构" class="headerlink" title="第二节 对象存储结构"></a>第二节 对象存储结构</h1><p>学习本节内容是为了搞清楚当线程在申请锁时，底层具体是如何工作的。</p>
<h2 id="1、对象存储结构"><a href="#1、对象存储结构" class="headerlink" title="1、对象存储结构"></a>1、对象存储结构</h2><p>现在我们都知道了对象（包括数组）都是放在堆内存中，那么对象在堆内存中保存时的数据结构是什么样子的呢？</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-07.jpg?versionId=CAEQKRiBgMCVsf2i.xciIDBmZjU2NGJhN2U0YTRiYWRhZDU1YzFiYjZjOWE0NzYz" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="①对象头"><a href="#①对象头" class="headerlink" title="①对象头"></a>①对象头</h3><ul>
<li>非数组对象<ul>
<li>Mark Word</li>
<li>类型指针</li>
</ul>
</li>
<li>数组<ul>
<li>Mark Word</li>
<li>类型指针</li>
<li>数组长度</li>
</ul>
</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-08.jpg?versionId=CAEQKRiBgICSsf2i.xciIGYwYzE2OGM3NjBlODRhOGRiOThhNjllYzQ2NWE4NzZj" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="②对象体"><a href="#②对象体" class="headerlink" title="②对象体"></a>②对象体</h3><p>这一部分也称为：实例数据。也就是对象中实际包含的属性数据。</p>
<h3 id="③对齐字节"><a href="#③对齐字节" class="headerlink" title="③对齐字节"></a>③对齐字节</h3><p>为了寻址方便，JVM 要求每一个对象起始地址必须是 8 字节的整数倍，也就是要求每一个对象的存储空间都是 8 字节的整数倍。所以对于占空间不满足这一要求的对象会进行填充。所以这一部分是不一定存在的。</p>
<h2 id="2、Mark-Word"><a href="#2、Mark-Word" class="headerlink" title="2、Mark Word"></a>2、Mark Word</h2><p>Mark Word 部分用于存储对象自身运行时数据，如哈希码、GC分代年龄等，这部分数据的长度在 32 位和 64 位的虚拟机中分别为 32 位和 64 位。</p>
<p>由于对象头的信息是与对象自身定义的数据没有关系的额外存储成本，因此考虑到 JVM 的空间效率，Mark Word 被设计成为一个非固定的数据结构，以便存储更多有效的数据，它会根据对象本身的状态复用自己的存储空间。</p>
<p>在 Mark Word 各种状态下的数据结构中，我们首先要关注一个数据：<strong>锁标识位</strong>。下面表格需要大家记住：</p>
<table>
<thead>
<tr>
<th align="center">锁标识位数值</th>
<th align="center">是否偏向</th>
<th align="center">锁标识位含义</th>
</tr>
</thead>
<tbody><tr>
<td align="center">01</td>
<td align="center">0</td>
<td align="center">无锁状态</td>
</tr>
<tr>
<td align="center">01</td>
<td align="center">1</td>
<td align="center">偏向锁状态</td>
</tr>
<tr>
<td align="center">00</td>
<td align="center">——</td>
<td align="center">轻量级锁状态</td>
</tr>
<tr>
<td align="center">10</td>
<td align="center">——</td>
<td align="center">重量级锁状态</td>
</tr>
<tr>
<td align="center">11</td>
<td align="center">——</td>
<td align="center">GC状态</td>
</tr>
</tbody></table>
<p>TIP</p>
<p>Mark Word 的存储结构对应五种状态。同一时刻它只可能是五种状态中的其中一种，所以没有必要把 Mark Word 分成五份儿分别保存这五种状态。Mark Word 在每一个时刻只需要保存当前状态的数据即可。每一种状态保存的数据结构不同。</p>
<p>所以 Mark Word 这同一块存储空间，在不同的状态下，有不同数据结构。</p>
<h3 id="①无锁状态"><a href="#①无锁状态" class="headerlink" title="①无锁状态"></a>①无锁状态</h3><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-09.jpg?versionId=CAEQKRiBgICOsf2i.xciIGQ3YmY2ZTI0ZGJkMDQyYzJhZGYyZDQwN2M3MTlkOTRk" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="②偏向锁状态"><a href="#②偏向锁状态" class="headerlink" title="②偏向锁状态"></a>②偏向锁状态</h3><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-10.jpg?versionId=CAEQKRiBgMCNsf2i.xciIGJiOTJhNTZiYWQ4ODQyMGZhZmMyMDRjZmYzMjE1YzJj" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="③轻量级锁状态"><a href="#③轻量级锁状态" class="headerlink" title="③轻量级锁状态"></a>③轻量级锁状态</h3><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-11.jpg?versionId=CAEQKRiBgMD4sP2i.xciIDdiMmM0NTlmMTMwYzRlMGFhM2Q1ZmE4MTBkZDIyODVm" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="④重量级锁状态"><a href="#④重量级锁状态" class="headerlink" title="④重量级锁状态"></a>④重量级锁状态</h3><p>这里我们看到了下一个非常重要的数据：指向<strong>对象监视器</strong>的指针。当前对象是由哪一个线程所锁定就是由这个对象监视器来记录的。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-12.jpg?versionId=CAEQKRiBgID0sP2i.xciIGZlNzVhMzI4MDg0OTQ2M2NhMjNhYTlmY2UwZTNkZDY1" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="⑤GC-状态"><a href="#⑤GC-状态" class="headerlink" title="⑤GC 状态"></a>⑤GC 状态</h3><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-13.jpg?versionId=CAEQKRiBgMD3sP2i.xciIDQ2ZjgyM2ZmYzQ0MzQxODJhMGE2ODE2NzMzYWUwMDAy" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="3、对象监视器"><a href="#3、对象监视器" class="headerlink" title="3、对象监视器"></a>3、对象监视器</h2><p>从上面的介绍中我们发现：当锁状态膨胀为『重量级锁』时，Mark Word 中有一个指针指向一个特殊的对象——对象监视器。这个对象是由 C++ 开发的，原名 ObjectMonitor。</p>
<h3 id="①锁对象和对象监视器之间的关系"><a href="#①锁对象和对象监视器之间的关系" class="headerlink" title="①锁对象和对象监视器之间的关系"></a>①锁对象和对象监视器之间的关系</h3><p>假设有如下代码：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-14.jpg?versionId=CAEQKRiBgIDxsP2i.xciIGEyMTQ4NzdkYzBhYTRkNjZhMTBmYmY4OGQyZGQ0NjY1" srcset="/img/loading.gif" lazyload alt="images"></p>
<p>其中 this 就是我们这里所说的锁对象。而就是通过这个锁对象的对象头，我们一步一步找到了它关联的 ObjectMonitor 对象监视器对象。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-15.jpg?versionId=CAEQKRiBgIDwsP2i.xciIGI0NzQ5NDE0ZDA0NTQxOTViNWRkMjE0ZTkxNWY2YWZi" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="②监视器对象结构"><a href="#②监视器对象结构" class="headerlink" title="②监视器对象结构"></a>②监视器对象结构</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs text">ObjectMonitor() &#123;<br>    _header       = NULL;<br>    _count        = 0;  // 锁计数器<br>    _waiters      = 0;<br>    _recursions   = 0; // 锁的重入次数<br>    _object       = NULL;<br>    _owner        = NULL; // 指向持有 ObjectMonitor 对象的线程<br>    _WaitSet      = NULL; // 处于 wait 状态的线程，会被加入到 _WaitSet（等待队列）<br>    _WaitSetLock  = 0 ;<br>    _Responsible  = NULL ;<br>    _succ         = NULL ;<br>    _cxq          = NULL ;<br>    FreeNext      = NULL ;<br>    _EntryList    = NULL ; // 处于等待锁 block 状态的线程，会被加入到该列表（阻塞队列）<br>    _SpinFreq     = 0 ;<br>    _SpinClock    = 0 ;<br>    OwnerIsThread = 0 ;<br>  &#125;<br></code></pre></td></tr></table></figure>

<h1 id="第三节-加锁和解锁流程"><a href="#第三节-加锁和解锁流程" class="headerlink" title="第三节 加锁和解锁流程"></a>第三节 加锁和解锁流程</h1><h2 id="1、monitorenter指令和monitorexit指令"><a href="#1、monitorenter指令和monitorexit指令" class="headerlink" title="1、monitorenter指令和monitorexit指令"></a>1、monitorenter指令和monitorexit指令</h2><p>为什么重量级锁能够通过锁对象把线程锁住呢？这里需要看看 <strong>monitor****enter</strong> 和 <strong>monitor****exit</strong> 这两个指令。那这两个指令是从哪来的呢？</p>
<h3 id="①字节码指令分析"><a href="#①字节码指令分析" class="headerlink" title="①字节码指令分析"></a>①字节码指令分析</h3><p>首先假定我们有如下代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo06CodeTest</span> </span>&#123;<br>    <br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSth</span><span class="hljs-params">()</span> </span>&#123;<br><br>        <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) &#123;<br>            System.out.println(<span class="hljs-string">&quot;Hello&quot;</span>);<br>        &#125;<br>        <br>    &#125;<br><br>&#125;<br></code></pre></td></tr></table></figure>

<p>然后编译：</p>
<blockquote>
<p>javac Demo06CodeTest.java</p>
</blockquote>
<p>然后针对字节码文件执行 javap 分析：</p>
<blockquote>
<p>javap -c Demo06CodeTest.class</p>
</blockquote>
<p>分析结果如下：</p>
<blockquote>
<p>Compiled from “Demo06CodeTest.java”<br>public class com.atguigu.thread.demo.Demo06CodeTest {<br>public com.atguigu.thread.demo.Demo06CodeTest();<br>Code:<br>0: aload_0<br>1: invokespecial #1 // Method java/lang/Object.”<init>“: ()V<br>4: return</init></p>
<p>public void doSth();<br>Code:<br>0: aload_0<br>1: dup<br>2: astore_1<br>3: <strong>monitor****enter</strong><br>4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;<br>7: ldc #3 // String Hello<br>9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V<br>12: aload_1<br>13: <strong>monitor****exit</strong><br>14: goto 22<br>17: astore_2<br>18: aload_1<br>19: <strong>monitor****exit</strong><br>20: aload_2<br>21: athrow<br>22: return<br>Exception table:<br>from to target type<br>4 14 17 any<br>17 20 17 any<br>}</p>
</blockquote>
<h3 id="②对应关系"><a href="#②对应关系" class="headerlink" title="②对应关系"></a>②对应关系</h3><p>这里的对应关系只是辅助我们理解，很显然代码实际执行时并不是遇到 synchronized 就执行 monitorenter，毕竟线程先要拿到锁才能加注解的锁。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-16.jpg?versionId=CAEQKRiBgIDvsP2i.xciIDBkNjk1YTdlMzk2YTRkMzU5MWFkMjQyZjdjMzdmNmI4" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="③执行过程"><a href="#③执行过程" class="headerlink" title="③执行过程"></a>③执行过程</h3><p>当线程在执行代码的过程中遇到了 synchronized，接下来它会这样做：</p>
<h4 id="1-根据锁对象找到对象监视器"><a href="#1-根据锁对象找到对象监视器" class="headerlink" title="[1]根据锁对象找到对象监视器"></a>[1]根据锁对象找到对象监视器</h4><p>不管是同步方法还是同步代码块，一定有一个锁对象，这个咱们前面说过了。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-17.jpg?versionId=CAEQKRiBgICzr_2i.xciIDQwMTVlOGJiYjM4YjRhMWJiY2NkMDE1ZjkxMDk0Y2Vh" srcset="/img/loading.gif" lazyload alt="images"></p>
<h4 id="2-加锁或阻塞"><a href="#2-加锁或阻塞" class="headerlink" title="[2]加锁或阻塞"></a>[2]加锁或阻塞</h4><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-18.jpg?versionId=CAEQKRiBgMC5r_2i.xciIDYzYjBkNGY4NTY0NjRjMjRiYTVmZjBhYTJhZWE1NWMy" srcset="/img/loading.gif" lazyload alt="images"></p>
<h4 id="3-执行代码"><a href="#3-执行代码" class="headerlink" title="[3]执行代码"></a>[3]执行代码</h4><p>即使是被阻塞了也还是会有机会得到锁，得到锁之后当然就是执行同步代码了。代码执行完成就要把锁释放掉。</p>
<h4 id="4-释放锁"><a href="#4-释放锁" class="headerlink" title="[4]释放锁"></a>[4]释放锁</h4><p>执行 <strong>monitor****exit</strong> 指令：</p>
<ul>
<li>_count - 1<ul>
<li>如果 - 1 后 _count 为零则擦除 _owner</li>
</ul>
</li>
<li>_recursions - 1</li>
</ul>
<h2 id="2、可重入性"><a href="#2、可重入性" class="headerlink" title="2、可重入性"></a>2、可重入性</h2><p>在刚才的分析中不知大家是否会提出一个疑问：为什么在 _count 大于零表示当前对象已锁定时，通过 _owner 能看到是自己锁定的呢？这肯定是因为自己曾经进来过，现在至少是第二次进来了。看下面的例子：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) &#123;<br>    <br>    <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) &#123;<br>        <span class="hljs-comment">// ...</span><br>    &#125;<br>    <br>&#125;<br></code></pre></td></tr></table></figure>



<p>从一个同步代码块又进入下一个同步代码块，这种现象我们称之为：『重入』。而多线程执行过程中如果不支持∶『可重入』，那将会发生死锁的问题。</p>
<h3 id="①假设不支持可重入"><a href="#①假设不支持可重入" class="headerlink" title="①假设不支持可重入"></a>①假设不支持可重入</h3><p>自己把自己锁住：陷入死循环。</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-19.jpg?versionId=CAEQKRiCgICzr_2i.xciIDlmMTIyNGI2OWI0ZjQzNDE4OGJiNDA5NDkyZjIwNGM5" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="②可重入性"><a href="#②可重入性" class="headerlink" title="②可重入性"></a>②可重入性</h3><p>所以线程执行时必须支持可重入性。所谓可重入性就是指：一个线程在获得锁之后如果再次进入同步代码，那么对于由它自己锁定的对象可以直接获得锁。具体来说就是：</p>
<ul>
<li>_owner 保持指向当前线程不变</li>
<li>_count 继续 + 1</li>
<li>_recursions 继续 + 1</li>
</ul>
<p>而当内层的 synchronized 需要释放锁时执行：</p>
<ul>
<li>_owner 保持指向当前线程不变</li>
<li>_count - 1</li>
<li>_recursions - 1</li>
</ul>
<p>当最外层的 synchronized 需要释放锁时执行：</p>
<ul>
<li>_owner 擦除</li>
<li>_count - 1，让 _count 回到 0</li>
<li>_recursions - 1，让 _recursions 回到 0</li>
</ul>
<p>结论：<strong>可重入性就是指一个线程可以直接获得它自己加的锁</strong>。大家要理解这个概念。</p>
<h3 id="③如果内外锁对象不同"><a href="#③如果内外锁对象不同" class="headerlink" title="③如果内外锁对象不同"></a>③如果内外锁对象不同</h3><p>各自执行各自的加锁流程</p>
<ul>
<li>拿到锁就执行同步代码块<ul>
<li>没拿到锁就阻塞</li>
</ul>
</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-20.jpg?versionId=CAEQKRiBgMCkr_2i.xciIGE2MmU0MmRkZGJlOTQ1ZTFiZjg2MjQ4ZDI1YmM5MDk4" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="④内外锁对象不同导致死锁的例子"><a href="#④内外锁对象不同导致死锁的例子" class="headerlink" title="④内外锁对象不同导致死锁的例子"></a>④内外锁对象不同导致死锁的例子</h3><p>两个线程分别进入 if 分支和 else 分支：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">//进行化妆</span><br><span class="hljs-function"><span class="hljs-keyword">public</span>  <span class="hljs-keyword">void</span>  <span class="hljs-title">makeup</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> InterruptedException </span>&#123;<br>    <span class="hljs-keyword">if</span> (choice==<span class="hljs-number">0</span>)&#123; <span class="hljs-comment">//为0时先获得了口红</span><br>        <span class="hljs-comment">//这里获得了口红后,除非获得了镜子,否则不释放口红锁</span><br>        <span class="hljs-keyword">synchronized</span> (lipstick)&#123;<br>            System.out.println(name+<span class="hljs-string">&quot;获得了口红&quot;</span>);<br>            Thread.sleep(<span class="hljs-number">1000</span>);<br>            <span class="hljs-keyword">synchronized</span> (mirror)&#123;<br>                System.out.println(name+<span class="hljs-string">&quot;获得了镜子&quot;</span>);<br>            &#125;<br>        &#125;<br><br><br>    &#125;<span class="hljs-keyword">else</span> &#123;<br>        <span class="hljs-comment">//这里获得了镜子后,除非获得了口红,否则不释放镜子锁</span><br>        <span class="hljs-keyword">synchronized</span> (mirror)&#123;<br>            System.out.println(name+<span class="hljs-string">&quot;获得了镜子&quot;</span>);<br>            Thread.sleep(<span class="hljs-number">2000</span>);<br>            <span class="hljs-keyword">synchronized</span> (lipstick)&#123;<br>                System.out.print(name+<span class="hljs-string">&quot;获得了口红&quot;</span>);<br>            &#125;<br>        &#125;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="3、补充问题：为什么monitorexit出现两次？"><a href="#3、补充问题：为什么monitorexit出现两次？" class="headerlink" title="3、补充问题：为什么monitorexit出现两次？"></a>3、补充问题：为什么monitorexit出现两次？</h2><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-21.jpg?versionId=CAEQKRiBgMCfr_2i.xciIDk0YWU1NzRlMmE5MzQzMThhZTRlY2FkOTJmZTVlMmE1" srcset="/img/loading.gif" lazyload alt="images"></p>
<h2 id="4、使用-ClassLayout-查看锁标记状态"><a href="#4、使用-ClassLayout-查看锁标记状态" class="headerlink" title="4、使用 ClassLayout 查看锁标记状态"></a>4、使用 ClassLayout 查看锁标记状态</h2><p>本节是通过实际程序的运行来辅助大家理解，不做强制要求。我们这里演示效果的测试环境是：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-22.jpg?versionId=CAEQKRiBgICbr_2i.xciIDA3ZTcwMjM4YmZhZjQwNzI4M2JhNmEzNGVjNDFhNWFh" srcset="/img/loading.gif" lazyload alt="images"></p>
<h3 id="①依赖信息"><a href="#①依赖信息" class="headerlink" title="①依赖信息"></a>①依赖信息</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.openjdk.jol<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jol-core<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span><br>    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.16<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span><br><span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span><br></code></pre></td></tr></table></figure>

<h3 id="②核心代码"><a href="#②核心代码" class="headerlink" title="②核心代码"></a>②核心代码</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// lockObject 是一个锁对象</span><br>System.out.println(ClassLayout.parseInstance(lockObject).toPrintable());<br></code></pre></td></tr></table></figure>

<h3 id="③测试代码"><a href="#③测试代码" class="headerlink" title="③测试代码"></a>③测试代码</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">// 创建锁对象（main 方法中没有 this，所以自己创建）</span><br>Object lockObject = <span class="hljs-keyword">new</span> Object();<br><br><span class="hljs-comment">// 直接打印对象结构</span><br>System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; &quot;</span> + ClassLayout.parseInstance(lockObject).toPrintable());<br><br><span class="hljs-comment">// 加同步代码块，再次打印对象结构</span><br><span class="hljs-keyword">synchronized</span> (lockObject) &#123;<br>    System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; &quot;</span> + ClassLayout.parseInstance(lockObject).toPrintable());<br>&#125;<br><br><span class="hljs-comment">// 开启一个新的线程申请锁</span><br><span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>    <span class="hljs-keyword">synchronized</span> (lockObject) &#123;<br>        <span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) &#123;<br>            <span class="hljs-keyword">try</span> &#123;TimeUnit.SECONDS.sleep(<span class="hljs-number">2</span>);&#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;&#125;<br><br>            <span class="hljs-comment">// 在同步代码块内打印对象结构</span><br>            System.out.println(Thread.currentThread().getName() + <span class="hljs-string">&quot; &quot;</span> + ClassLayout.parseInstance(lockObject).toPrintable());<br>        &#125;<br>    &#125;<br>&#125;, <span class="hljs-string">&quot;AAA&quot;</span>).start();<br><br><span class="hljs-keyword">try</span> &#123;<br>    <span class="hljs-comment">// 这里等待一会儿是为了让 AAA 线程先在较低的锁级别执行一段时间</span><br>    TimeUnit.SECONDS.sleep(<span class="hljs-number">3</span>);<br>&#125; <span class="hljs-keyword">catch</span> (InterruptedException e) &#123;<br>    e.printStackTrace();<br>&#125;<br><br><span class="hljs-comment">// 开启一个新的线程申请锁</span><br><span class="hljs-keyword">new</span> Thread(()-&gt;&#123;<br>    <span class="hljs-keyword">synchronized</span> (lockObject) &#123;<br>        <span class="hljs-comment">// 新建一个 BBB 线程是为了竞争锁，</span><br>        <span class="hljs-comment">// 但是由于 AAA 线程是 while (true) 执行，永远不会释放锁</span><br>        <span class="hljs-comment">// 所以 BBB 线程内部什么都不用做，只要去竞争就能让 AAA 线程的锁膨胀</span><br>    &#125;<br>&#125;, <span class="hljs-string">&quot;BBB&quot;</span>).start();<br></code></pre></td></tr></table></figure>



<h3 id="④膨胀过程"><a href="#④膨胀过程" class="headerlink" title="④膨胀过程"></a>④膨胀过程</h3><table>
<thead>
<tr>
<th>标识符</th>
<th>含义</th>
</tr>
</thead>
<tbody><tr>
<td>non-biasable</td>
<td>不可偏向</td>
</tr>
<tr>
<td>biasable</td>
<td>可偏向</td>
</tr>
<tr>
<td>biased</td>
<td>已偏向</td>
</tr>
<tr>
<td>thin lock</td>
<td>轻量级锁</td>
</tr>
<tr>
<td>fat lock</td>
<td>重量级锁</td>
</tr>
</tbody></table>
<h4 id="1-未开启偏向锁功能"><a href="#1-未开启偏向锁功能" class="headerlink" title="[1]未开启偏向锁功能"></a>[1]未开启偏向锁功能</h4><blockquote>
<p>main java.lang.Object object internals:<br>OFF SZ TYPE DESCRIPTION VALUE<br>0 8 (object header: mark) 0x0000000000000001 (<strong>non-biasable</strong>; age: 0)<br>8 4 (object header: class) 0xf80001e5<br>12 4 (object alignment gap)<br>Instance size: 16 bytes<br>Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</p>
<p>main java.lang.Object object internals:<br>OFF SZ TYPE DESCRIPTION VALUE<br>0 8 (object header: mark) 0x000000000288f4f8 (<strong>thin lock</strong>: 0x000000000288f4f8)<br>8 4 (object header: class) 0xf80001e5<br>12 4 (object alignment gap)<br>Instance size: 16 bytes<br>Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</p>
<p>AAA java.lang.Object object internals:<br>OFF SZ TYPE DESCRIPTION VALUE<br>0 8 (object header: mark) 0x00000000234bf2d8 (<strong>thin lock</strong>: 0x00000000234bf2d8)<br>8 4 (object header: class) 0xf80001e5<br>12 4 (object alignment gap)<br>Instance size: 16 bytes<br>Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</p>
<p>AAA java.lang.Object object internals:<br>OFF SZ TYPE DESCRIPTION VALUE<br>0 8 (object header: mark) 0x0000000002b8c46a (<strong>fat lock</strong>: 0x0000000002b8c46a)<br>8 4 (object header: class) 0xf80001e5<br>12 4 (object alignment gap)<br>Instance size: 16 bytes<br>Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</p>
</blockquote>
<h4 id="2-开启偏向锁功能"><a href="#2-开启偏向锁功能" class="headerlink" title="[2]开启偏向锁功能"></a>[2]开启偏向锁功能</h4><h5 id="1-设置-JVM-参数"><a href="#1-设置-JVM-参数" class="headerlink" title="(1)设置 JVM 参数"></a>(1)设置 JVM 参数</h5><blockquote>
<p><strong>-XX:+UseBiasedLocking</strong><br><strong>-XX:BiasedLockingStartupDelay=0</strong></p>
</blockquote>
<ul>
<li>-XX:+UseBiasedLocking 表示开启偏向锁功能</li>
<li>-XX:BiasedLockingStartupDelay=0 表示延迟开启偏向锁功能的时间为 0</li>
</ul>
<h5 id="2-代码运行效果"><a href="#2-代码运行效果" class="headerlink" title="(2)代码运行效果"></a>(2)代码运行效果</h5><blockquote>
<p>main java.lang.Object object internals:<br>OFF SZ TYPE DESCRIPTION VALUE<br>0 8 (object header: mark) 0x0000000000000005 (<strong>biasable</strong>; age: 0)<br>8 4 (object header: class) 0xf80001e5<br>12 4 (object alignment gap)<br>Instance size: 16 bytes<br>Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</p>
<p>main java.lang.Object object internals:<br>OFF SZ TYPE DESCRIPTION VALUE<br>0 8 (object header: mark) 0x00000000025ee005 (<strong>biased</strong>: 0x00000000000097b8; epoch: 0; age: 0)<br>8 4 (object header: class) 0xf80001e5<br>12 4 (object alignment gap)<br>Instance size: 16 bytes<br>Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</p>
<p>AAA java.lang.Object object internals:<br>OFF SZ TYPE DESCRIPTION VALUE<br>0 8 (object header: mark) 0x00000000236bf568 (<strong>thin lock</strong>: 0x00000000236bf568)<br>8 4 (object header: class) 0xf80001e5<br>12 4 (object alignment gap)<br>Instance size: 16 bytes<br>Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</p>
<p>AAA java.lang.Object object internals:<br>OFF SZ TYPE DESCRIPTION VALUE<br>0 8 (object header: mark) 0x0000000020e2e17a (<strong>fat lock</strong>: 0x0000000020e2e17a)<br>8 4 (object header: class) 0xf80001e5<br>12 4 (object alignment gap)<br>Instance size: 16 bytes<br>Space losses: 0 bytes internal + 4 bytes external = 4 bytes total</p>
</blockquote>
<h2 id="5、小结"><a href="#5、小结" class="headerlink" title="5、小结"></a>5、小结</h2><p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-23.jpg?versionId=CAEQKRiBgICrr_2i.xciIGE5NDA3YWE2NjY4NzRjMWJiOTcyNTFiNGRlYzg2YmRh" srcset="/img/loading.gif" lazyload alt="images"></p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/JUC/JUC02-24.png?versionId=CAEQKRiBgMC33bLH.xciIGEwYjE2ZGY2OTQ3OTRjMjZhNjUwZjBhYTA3MWU5ZTky" srcset="/img/loading.gif" lazyload alt="image-20220308215051724"></p>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/JUC/">JUC</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/JUC/">JUC</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客目前大部分文章都是参考尚硅谷或者马士兵教育的学习资料！<a href="http://www.atguigu.com/" rel="nofollow noopener"官网地址！</a> 
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/03/08/JUC03-LockApi/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">JUC学习笔记（三）Lock API控制多线程</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/03/07/JUC01-Thread/">
                        <span class="hidden-mobile">JUC学习笔记（一）多线程基本知识</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments" lazyload>
                
                  
                
                

              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">

  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
	<!--《添加网站运行时间 -->
<br/>

<span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>
<script>
var now = new Date(); 

function createtime() {
    //此处修改你的建站时间或者网站上线时间
    var grt = new Date('11/02/2021 21:39:00');
    now.setTime(now.getTime() + 250);
    days = (now - grt) / 1000 / 60 / 60 / 24;

    dnum = Math.floor(days);
    hours = (now - grt) / 1000 / 60 / 60 - (24 * dnum);
    hnum = Math.floor(hours);
    if (String(hnum).length == 1) {
        hnum = "0" + hnum;
    }
    minutes = (now - grt) / 1000 / 60 - (24 * 60 * dnum) - (60 * hnum);
    mnum = Math.floor(minutes);
    if (String(mnum).length == 1) {
        mnum = "0" + mnum;
    }
    seconds = (now - grt) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
    snum = Math.round(seconds);
    if (String(snum).length == 1) {
        snum = "0" + snum;
    }
    document.getElementById("timeDate").innerHTML = " 本站已各种夹缝中安全运行 " + dnum + " 天 ";
    document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
}
setInterval("createtime()", 250);
</script>

<!-- 添加网站运行时间》-->
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
